package com.example.basic.service.impl;

import com.example.basic.controller.dto.FileDTO;
import com.example.basic.controller.dto.SocketPayloadDTO;
import com.example.basic.controller.dto.TaskDTO;
import com.example.basic.dao.UserMapper;
import com.example.basic.domain.Games;
import com.example.basic.domain.User;
import com.example.basic.service.TestService;
import com.example.basic.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.io.*;
import java.net.Socket;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author mjw
 * @date 2023/8/28
 */
@Service
@Slf4j
public class TestServiceImpl implements TestService {

    private final UserMapper userMapper;
    private final UserService userService;
    private final RestTemplate restTemplate;
    private final Validator validator;

    @Autowired
    public TestServiceImpl(UserMapper userMapper, UserService userService, RestTemplate restTemplate, Validator validator) {
        this.userMapper = userMapper;
        this.userService = userService;
        this.restTemplate = restTemplate;
        this.validator = validator;
    }


    @Override
    public void syncTest() throws InterruptedException {
        TimeUnit.SECONDS.sleep(5);
        System.out.println("模拟执行完毕......");
    }

    @Override
//    @Transactional
    public void testTransaction() {
        // 1. 模拟校验
        checkThis();

//        ((TestServiceImpl)(AopContext.currentProxy())).addStep2();

        addStep2();

        ((TestServiceImpl) (AopContext.currentProxy())).addStep1();

    }


    public void checkThis() {
        System.out.println("checkThis--->");
    }

    @Override
    @Transactional
    public void addStep1() {
        userMapper.addUser(new User() {{
            setName("1");
            setAge(1);
            setSex("1");
            setDescription("1");
        }});
        add1();
//        ((TestServiceImpl)(AopContext.currentProxy())).add1();
    }

    @Transactional
    public void add1() {
        addStep1_1();
        addStep1_2();
    }

    @Override
    public void addStep1_1() {
        userMapper.addUser(new User() {{
            setName("1-1");
            setAge(1);
            setSex("1");
            setDescription("1-1");
        }});
    }

    @Override
    public void addStep1_2() {
        userMapper.addUser(new User() {{
            setName("1-2");
            setAge(1);
            setSex("1");
            setDescription("1-2");
        }});
//        try {
//            throw new RuntimeException();
//        }catch (Exception e) {
//            e.printStackTrace();
//        }

    }

    @Override
    @Transactional
    public void addStep2() {
        userMapper.addUser(new User() {{
            setName("2");
            setAge(2);
            setSex("2");
            setDescription("2");
        }});
        addXXX();
    }

    @Override
    public void openUrl(HttpServletResponse response) {
        String href = "https://www.feishu.cn/";
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> exchangeUrl = restTemplate.exchange(href, HttpMethod.GET, null, String.class);
        System.out.println(exchangeUrl.getBody());
    }

    @Override
    public Map<Integer, Map<Integer, String>> validateTemplate(HttpServletResponse response, MultipartFile excel) {
        InputStream inputStream = null;
        try {
            inputStream = excel.getInputStream();
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        Map<Integer, Map<Integer, String>> map = readHeader(inputStream, 0);
        return map;
    }

    @Override
    public String testApis() {
        String url1 = "http://197.166.174.134:8412/v2/choerodon/api-docs";
        String url2 = "http://197.166.174.169:8020/oauth/v2/choerodon/api-docs";
        String localUrl = "http://localhost:8000/user/getAll";
        ResponseEntity<String> forEntity = restTemplate.getForEntity(localUrl, String.class);
        System.out.println(forEntity.getStatusCode());
        System.out.println(forEntity.getBody());
        return localUrl;
    }

    @Override
    public List<String> validGames(Games games, BindingResult bindingResult) {
        List<String> errorList = validator.validate(games).stream().map(ConstraintViolation::getMessage).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(errorList)) {
            return errorList;
        }
//        if (bindingResult.hasErrors()) {
//            return bindingResult.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());
//        }
        List<String> successList = new ArrayList<>();
        successList.add("校验成功！");
        return successList;
    }

    @Override
    public void download(HttpServletRequest request, HttpServletResponse response) {
        try {
            FileInputStream is = new FileInputStream("/Users/majianwei/Downloads/Big size pdf.pdf");
//            ByteArrayOutputStream os = new ByteArrayOutputStream();
//            IOUtils.copy(is, os);
//            byte[] data = os.toByteArray();
            byte[] data = IOUtils.toByteArray(is);
            response.reset();
            response.setHeader("Content-Disposition", "attachment;filename=" + System.currentTimeMillis() + ".pdf");
            response.setContentType("multipart/form-data");
            response.addHeader("Content-Length", "" + data.length);
            response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
            response.setHeader("Pragma", "public");
            response.setDateHeader("Expires", System.currentTimeMillis() + 1000L);
//            IOUtils.write(data, response.getOutputStream());

            ThreadPoolExecutor executor = new ThreadPoolExecutor(
                    2,
                    2,
                    5,
                    TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(5),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.AbortPolicy());

            for (int i = 0; i < 10; i++) {
                FileOutputStream fos = new FileOutputStream("/Users/majianwei/Downloads/" + System.currentTimeMillis() + ".pdf");
                TaskDTO taskDTO = new TaskDTO();
                taskDTO.setTaskId(i);
                taskDTO.setFos(fos);
                taskDTO.setData(data);
                executor.submit(taskDTO);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void downloadPdf(HttpServletResponse response, String fileUrl) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        InputStream inputStream = null;
        try {
            ResponseEntity<Resource> entity = downloadFile(fileUrl);

            //设置响应头
            response.addHeader(HttpHeaders.CONTENT_DISPOSITION,entity.getHeaders().getContentDisposition().toString());
            //边下边response
            inputStream = entity.getBody().getInputStream();
//            outputStream = response.getOutputStream();
            int len;
            int count = 0;
            byte[] buffer = new byte[1024];
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
                count++;
                if (count % 10 == 0){
                    outputStream.flush();
                }
            }
            inputStream.close();
            response.flushBuffer();
            outputStream.close();
            byte[] bytes = outputStream.toByteArray();
            System.out.println(Arrays.toString(bytes));
            ServletOutputStream os = response.getOutputStream();
            os.write(bytes);
            os.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String validJson(Games games) {
        return "ok!";
    }

    @Override
    public void downloadZip(HttpServletResponse response, List<FileDTO> fileDTOList) {
        ZipOutputStream out = null;
        try {
            out = new ZipOutputStream(response.getOutputStream());
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("附件p.zip", "UTF-8"));
            response.setContentType("multipart/form-data");
            for (FileDTO fileDTO : fileDTOList) {
                InputStream inputStream = downloadFile(fileDTO.getFileUrl()).getBody().getInputStream();
                try {
                    // 创建压缩文件
                    if (Objects.nonNull(inputStream)) {
                        out.putNextEntry(new ZipEntry(fileDTO.getFileName()));
                        byte[] buffer = new byte[1024];
                        int len;
                        while ((len = inputStream.read(buffer)) != -1) {
                            out.write(buffer, 0, len);
                        }
                    }
                } catch (Exception e){
                    throw e;
                } finally{
                    inputStream.close();
                }
            }
        } catch (Exception e) {
            log.info("download file error--->{}", e.getMessage());
        } finally {
            if (Objects.nonNull(out)) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.info("download file error--->{}", e.getMessage());
                }
            }
        }
    }

    @Override
    public String socketInvoke(SocketPayloadDTO dto) {
        String response = null;
        try {
            response = socketSendAndReceive("192.168.137.166", 15999, dto.getPayload());
        } catch (Exception e) {
            log.error("socket call failed: {}", e.getMessage(), e);
        }
        return response;
//        HashMap<String, String> socketMap = new HashMap<>();
//        socketMap.put("ip", "192.168.137.166");
//        socketMap.put("port", "15999");
//        String response = null;
//        Socket socket = null;
//        InputStreamReader inputStreamReader = null;
//        BufferedReader bufferedReader = null;
//        PrintWriter printWriter = null;
//
//        try {
//            log.info("服务器接收请求:{}", dto.getPayload());
//            // 创建socket连接
//            socket = new Socket(socketMap.get("ip"), Integer.parseInt(socketMap.get("port")));
//            socket.setSoTimeout(5000);
//            // 打印输出流
//            printWriter = new PrintWriter(socket.getOutputStream());
//            printWriter.print(dto.getPayload());
//            printWriter.flush();
//
//            socket.shutdownOutput();
//
//            // 读取输出流
//            inputStreamReader = new InputStreamReader(socket.getInputStream());
//            bufferedReader = new BufferedReader(inputStreamReader);
//            String temp = "";
//            StringBuilder stringBuilder = new StringBuilder();
//
//            while ((temp = bufferedReader.readLine()) != null) {
//                stringBuilder.append(temp).append("\r\n");
//            }
//
//            response = stringBuilder.toString();
//            log.info("服务端返回消息:{}", response);
//        } catch (Exception e) {
//            log.error("socket call failed: {}", e.getMessage(), e);
//        } finally {
//            if (bufferedReader != null) {
//                try {
//                    bufferedReader.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//            if (inputStreamReader != null) {
//                try {
//                    inputStreamReader.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//            if (printWriter != null) {
//                printWriter.close();
//            }
//            if (socket != null) {
//                try {
//                    socket.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
//
//        return response;
    }


    private String socketSendAndReceive(String url, int port, String xmlData) throws Exception {
        System.out.println("请求数据：" + xmlData);
        Socket socket = new Socket(url, port);
        OutputStream bw = socket.getOutputStream();
        bw.write(xmlData.getBytes("gbk"));
        bw.flush();
        InputStream ips = socket.getInputStream();
        StringBuffer sb = new StringBuffer();
        int len = 0;
        byte[] buf = new byte[1024];
        while ((len = ips.read(buf)) != -1) {
            sb.append(new String(buf, 0, len, "gbk"));
        }
        bw.close();
        ips.close();
        socket.close();
        return sb.toString();
    }

    public ResponseEntity<Resource> downloadFile(String requestUrl) {
        RestTemplate restTemplate = new RestTemplate();
        //请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        //接口调用
        HttpEntity httpEntity = new HttpEntity(headers);
        ResponseEntity<Resource> entity = restTemplate.exchange(requestUrl, HttpMethod.GET, httpEntity, Resource.class);
        return entity;
    }

    public static Map<Integer, Map<Integer, String>> readHeader(InputStream inputStream, Integer sheetNo) {
        Workbook workbook;
        try {
            workbook = new SXSSFWorkbook(new XSSFWorkbook(inputStream));
            Sheet sheet;
            if (workbook instanceof SXSSFWorkbook) {
                SXSSFWorkbook sxssfWorkbook = (SXSSFWorkbook) workbook;
                sheet = sxssfWorkbook.getXSSFWorkbook().getSheetAt(sheetNo);
            } else {
                sheet = workbook.getSheetAt(sheetNo);
            }
            Map<Integer, Map<Integer, String>> contentMap = new HashMap<>();
            for (Row row : sheet) {
                int rowNum = row.getRowNum();
                Map<Integer, String> cellMap = new HashMap<>();
                // 一共有多少列（表头有多少个数据）
                int cellCount = row.getLastCellNum();
                for (int i = 0; i < cellCount; i++) {
                    Cell cell = row.getCell(i);
                    if (null == cell) {
                        cellMap.put(i, null);
                    } else {
                        cell.setCellType(CellType.STRING);
                        String cellValue = cell.getStringCellValue().trim();
                        cellMap.put(i, cellValue);
                    }
                }
                contentMap.put(rowNum, cellMap);
            }
            return contentMap;
            // 读取表头
//            Row headerRow = sheet.getRow(0);
//            // 存放表头信息
//            Map<Integer, String> cellMap = new HashMap<>();
//            // 一共有多少列（表头有多少个数据）
//            int cellCount = headerRow.getLastCellNum();
//            for (int i = 0; i < cellCount; i++) {
//                Cell cell = headerRow.getCell(i);
//                if (null == cell) {
//                    cellMap.put(i, null);
//                } else {
//                    cell.setCellType(CellType.STRING);
//                    String cellValue = cell.getStringCellValue().trim();
//                    cellMap.put(i, cellValue);
//                }
//            }
//            return cellMap;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public void addXXX() {
        userService.addUser(new User() {{
            setName("xxx");
            setAge(1);
            setSex("1");
            setDescription("xxx");
        }});
        throw new RuntimeException();
    }
}
